package com.fengwk.cv4j.factory.ind;

import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;

import com.fengwk.cv4j.compute.ind.INDCompute;
import com.fengwk.cv4j.factory.ViewFactoryImpl;
import com.fengwk.cv4j.view.Var;
import com.fengwk.cv4j.view.View;
import com.fengwk.cv4j.view.ind.INDArrayWrap;
import com.fengwk.cv4j.view.ind.INDMaxView;
import com.fengwk.cv4j.view.ind.INDMeanView;
import com.fengwk.cv4j.view.ind.INDMinView;
import com.fengwk.cv4j.view.ind.INDMmulView;
import com.fengwk.cv4j.view.ind.INDSumView;
import com.fengwk.support.exception.BaseException;
import com.fengwk.support.util.ArrayUtils;

public class INDViewFactory extends ViewFactoryImpl<INDArrayWrap> {

	public INDViewFactory() {
		super(new INDCompute());
	}
	
    public Var<INDArrayWrap> of(INDArray arr) {
        return of(new INDArrayWrap(arr));
    }
	
	@Override
	public Var<INDArrayWrap> of(Number num) {
		return of(new INDArrayWrap(num));
	}

	@Override
	public Var<INDArrayWrap> of(Number num, INDArrayWrap d) {
		Number n = d.num();
		if (n != null)
			return of(num);
		else {
			INDArray arr = d.arr();
			if (arr == null)
				throw new BaseException("arr == null");
			return of(Nd4j.valueArrayOf(arr.shape(), num.doubleValue()));
		}
	}
	
	/**
	 * 不推荐使用的方法</br>
	 * 这个方法应只在内部实现使用</br>
	 * 推荐使用{@link #mean(View, int...)}
	 */
	@Deprecated
	@Override
    public View<INDArrayWrap> mean(@SuppressWarnings("unchecked") View<INDArrayWrap>...vs) {
        return new INDMeanView(compute, this, vs);
    }

	/**
	 * 不推荐使用的方法</br>
	 * 这个方法应只在内部实现使用</br>
	 * 推荐使用{@link #sum(View, int...)}
	 */
	@Deprecated
    @Override
    public View<INDArrayWrap> sum(@SuppressWarnings("unchecked") View<INDArrayWrap>...vs) {
        return new INDSumView(compute, this, vs);
    }
    
	/**
	 * 不推荐使用的方法</br>
	 * 这个方法应只在内部实现使用</br>
	 * 推荐使用{@link #max(View, int...)}
	 */
	@Deprecated
    @Override
    public View<INDArrayWrap> max(@SuppressWarnings("unchecked") View<INDArrayWrap>...vs) {
        return new INDMaxView(compute, this, vs);
    }

	/**
	 * 不推荐使用的方法</br>
	 * 这个方法应只在内部实现使用</br>
	 * 推荐使用{@link #min(View, int...)}
	 */
	@Deprecated
    @Override
    public View<INDArrayWrap> min(@SuppressWarnings("unchecked") View<INDArrayWrap>...vs) {
        return new INDMinView(compute, this, vs);
    }

    /**
     * 求均值
     * 
     * @param v
     * @param dimension
     * @return
     */
    public View<INDArrayWrap> mean(View<INDArrayWrap> v, int... dimension) {
        return mean(toVs(v, dimension));
    }

    /**
     * 求和
     * 
     * @param v
     * @param dimension
     * @return
     */
    public View<INDArrayWrap> sum(View<INDArrayWrap> v, int... dimension) {
        return sum(toVs(v, dimension));
    }
    
    /**
     * 最大值
     * 
     * @param v
     * @param dimension
     * @return
     */
    public View<INDArrayWrap> max(View<INDArrayWrap> v, int... dimension) {
        return max(toVs(v, dimension));
    }
    
    /**
     * 最小值
     * 
     * @param v
     * @param dimension
     * @return
     */
    public View<INDArrayWrap> min(View<INDArrayWrap> v, int... dimension) {
        return min(toVs(v, dimension));
    }
	
	@SuppressWarnings("unchecked")
	public View<INDArrayWrap> mmul(View<INDArrayWrap> v1, View<INDArrayWrap> v2) {
		return new INDMmulView(compute, this, v1, v2);
	}
	
	private View<INDArrayWrap>[] toVs(View<INDArrayWrap> v, int... dimension) {
        if (ArrayUtils.isBlank(dimension))
            throw new BaseException("ArrayUtils.isBlank(dimension)");
        
        int len = 1 + dimension.length;
        @SuppressWarnings("unchecked")
        View<INDArrayWrap>[] vs = (View<INDArrayWrap>[]) new View<?>[len];
        vs[0] = v;
        for (int i = 1; i < len; i ++)
            vs[i] = of(dimension[i - 1]);
        
        return vs;
    }
	
}
